package com.briup.server;

import com.briup.Configuration;
import com.briup.entity.Environment;
import com.briup.support.ConfigurationAware;
import com.briup.support.PropertiesAware;
import com.briup.util.Backup;
import com.briup.util.BackupImpl;
import com.briup.util.Log;
import com.briup.util.LogImpl;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.stream.Collectors;

/**
 * 数据库入库时的数据备份
 */
public class DBStoreBackUpImpl implements DBStore, PropertiesAware, ConfigurationAware {

    private Log log;
    private String driverClassName;
    private String url;
    private String username;
    private String password;
    private String filePath;
    private Backup backup;

    @Override
    public void saveDB(Collection<Environment> collection) throws Exception {
        //可能上次入库出现异常  恢复数据

        log.debug("备份文件路径" + filePath);
        List<Environment> destObj = (List<Environment>) backup.load(filePath, Backup.LOAD_REMOVE);
        //如果有备份数据   将备份数据添加到入库数据
        if (destObj != null) {
            log.info("检测到备份数据文件");
            collection.addAll(destObj);
        }
        //入库逻辑
        //注册驱动
        Class.forName(driverClassName);
        Connection connection = null;
        PreparedStatement ps = null;
        //总提交数据 数量
        int commitCount = 0;
        try {
            //获取连接
            connection = DriverManager.getConnection(url, username, password);
            //设置手动提交
            connection.setAutoCommit(false);

            int day = 0;
            int dayCommitCount = 0;
            String sql = null;
            int i = 0;
            for (Environment environment : collection) {
//                if (i++ == 61000)
//                    throw new Exception("故意报错");
                //获取采集时间 中的日期
                int date = environment.getGatherDate().getDate();
                //检测 采集数据的日期发生变化
                if (day != date) {
                    day = date;
                    //处理前一天 未满足批处理 阈值的数据  但是要考虑 初始日期的变化
                    if (ps != null) {
                        ps.executeBatch();
                        ps.clearBatch();
                        //提交前一天的数据
                        connection.commit();
                        //累加已经提交的数据
                        commitCount += dayCommitCount;
                        log.info(day + "：入库数据" + dayCommitCount + "条");
                        dayCommitCount = 0;
                        ps.close();
                    }
                    //每一天的sql都不一样  因为日期的变化  导致sql不是同构语句  所以 ps也要变
                    sql = "insert into e_detail_" + day + "(id,name,srcId,descId,devId,count,cmd,status,data,gather_date) values(seq_" + day + ".nextval,?,?,?,?,?,?,?,?,?)";
                    //创建statement对象
                    ps = connection.prepareStatement(sql);
                }

                ps.setString(1, environment.getName());
                ps.setString(2, environment.getSrcId());
                ps.setString(3, environment.getDescId());
                ps.setString(4, environment.getDevId());
                ps.setInt(5, environment.getCount());
                ps.setString(6, environment.getCmd());
                ps.setInt(7, environment.getStatus());
                ps.setFloat(8, environment.getData());
                ps.setTimestamp(9, environment.getGatherDate());
                //添加sql到batch
                ps.addBatch();
                //因为数据量过大的批处理可能会导致数据丢失 所以每五千条处理一次
                if (dayCommitCount++ % 5000 == 0) {
                    ps.executeBatch();
                }
            }
            ps.executeBatch();
        } catch (Exception e) {
            e.printStackTrace();
            //当天的数据回滚
            connection.rollback();
            List<Environment> list = collection.stream().skip(commitCount).collect(Collectors.toList());
            //入库异常  数据备份
            backup.store(filePath, list, Backup.STORE_APPEND);
        } finally {
            if (connection != null)
                connection.close();
            if (ps != null)
                ps.close();
        }

    }

    @Override
    public void init(Properties properties) throws Exception {
        filePath = properties.getProperty("filePath");
        driverClassName = properties.getProperty("driverClassName");
        url = properties.getProperty("url");
        username = properties.getProperty("username");
        password = properties.getProperty("password");

    }

    @Override
    public void setConfiguration(Configuration configuration) throws Exception {
        log = configuration.getLogger();
        backup = configuration.getBackup();
    }
}
